package uk.ac.cam.juliet.zedcat.client;

import java.awt.image.BufferedImage;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

/**
 *
 * @author David Piggott
 */
public class Pipeline {

    private Configuration mConfiguration = new Configuration();
    private final BlockingQueue<Frame> mFreshFrames = new LinkedBlockingQueue<Frame>(mConfiguration.getQueueSize());
    private final BlockingQueue<Frame> mProcessedFrames = new LinkedBlockingQueue<Frame>(mConfiguration.getQueueSize());
    private final BlockingQueue<Frame> mStillProcessedFrames = new LinkedBlockingQueue<Frame>(mConfiguration.getQueueSize());
    private final BlockingQueue<Event> mEventQueue = new LinkedBlockingQueue<Event>(mConfiguration.getQueueSize());
    private final FrameViewer mFrameViewer = new FrameViewer(this, mConfiguration, mProcessedFrames, mStillProcessedFrames);
    private final FrameSource mFrameSource = new FrameSource(this, mConfiguration, mFreshFrames);
    private final FrameSubtractAndExtract mFrameSubtractAndExtract = new FrameSubtractAndExtract(this, mConfiguration, mFreshFrames, mProcessedFrames);
    private final EventQuantise mEventQuantiser = new EventQuantise(this, mConfiguration);
    private int mFramerate = 0;

    public void setBackground() {
        appendLine("Attempting to set background.");
        BufferedImage image = null;
        boolean success = false;
        try {
            image = mFrameSource.getImage();
            success = true;
        } catch (Exception e1) {
            while (!success) {
                appendLine("Error getting background from camera. Retrying in 10 seconds.");
                try {
                    Thread.sleep(10000);
                } catch (InterruptedException e2) {
                }
            }
        }
        appendLine("Background set complete.");
        mFrameSubtractAndExtract.setBackground(image);
    }

    public BufferedImage getBackground() {
        return mFrameSubtractAndExtract.getBackground();
    }

    public void appendLine(String line) {
        mFrameViewer.appendLine(line);
    }

    public void updateFramerate(int fR) {
        mFrameViewer.updateFramerate(fR);
    }

    public int getFramerate() {
        return mFramerate;
    }

    public Pipeline() {

        mFrameViewer.setVisible(true);

        final Pipeline p = this;


        final Runnable eventQuantise = new Runnable() {

            public void run() {
                while (true) {
                    try {
                        mEventQuantiser.addEvent(mEventQueue.take());
                    } catch (Exception e) {
                        //e.printStackTrace();
                    }
                }
            }
        };

        Runnable eventFactory = new Runnable() {

            public void run() {
                while (true) {
                    Frame f;
                    try {
                        f = mStillProcessedFrames.take();
                        if (f.getRegions().size() == 0) {
                            mEventQueue.add(new Event());
                            //p.appendLine("empty frame");
                        } else {
                            for (Region reg : f.getRegions()) {
                                mEventQueue.add(EventFactory.ProcessRegion(reg, mConfiguration, p));
                            }
                        }
                    } catch (Exception e) {
                        //e.printStackTrace();
                    }
                }
            }
        };

        new Thread(mFrameSource).start();
        new Thread(mFrameSubtractAndExtract).start();
        new Thread(mFrameViewer).start();
        new Thread(eventFactory).start();
        new Thread(eventQuantise).start();

    }
}
